#include<bits/stdc++.h>
using namespace std;
void read() {}
template<class T, class... Arg>
void read(T &x, Arg&&... args) {
	cin >> x;
	read(args...);
}
void print_err() {
	cerr << "\n";
}
template <class T, class... Arg>
void print_err(T x, Arg&&... args) {
	cerr << x << " ";
	print_err(args...);
}
template<class T>
void print_container(T &cont) {
	for (auto iter : cont) {
		cerr << iter << " ";
	}
	cerr << "\n";
}
#ifdef local
#define debug(...) print_err(__VA_ARGS__)
#define debug_c(container) print_container(container)
#else
#define debug(...)
#define debug_c(container)
#endif
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// using namespace __gnu_pbds;
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
#define mod 1000000007
#define ll long long int
#define ff first
#define ss second
#define pb push_back
#define mp make_pair
#define pll pair<ll,ll>
#define vl vector<ll>
#define vpll vector<pair<ll,ll>>
#define mll map<ll,ll>
#define mllrev map<ll,ll,greater<int>>
#define ps(x,y) fixed<<setprecision(y)<<x//it will give upto y decimal places
#define w(t) ll t;cin>>t;while(t--)
#define fo(i,n) for(ll i=0;i<n;++i)
#define foab(i,a,b) for(ll i=a;i<b;++i)
#define inp cin>>
#define pr cout<<
#define pqb priority_queue<ll>//max heap
#define pqs priority_queue<ll,vl,greater<int>>//min heap
#define mk(arr,n,type) type *arr=new type[n];
#define all(A) (A).begin(),(A).end()
#define fastio ios_base::sync_with_stdio(NULL);cin.tie(NULL);cout.tie(NULL);
void CP() {
	fastio
#ifdef local
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
	freopen("error.txt", "w", stderr);
#endif
	return;
}
class Graph {
public:
	list<ll> *adj_list;
	ll v;
	Graph(ll v) {
		this->v = v;
		adj_list = new list<ll>[v];
	}
	void add_edge(ll u, ll v, bool bidirectional = true) {
		adj_list[u].push_back(v);
		if (bidirectional) {
			adj_list[v].push_back(u);
		}
	}
	void print();
	void connected_compo();
	void dfs(vector<vector<ll>> vect, ll k1, ll k2, ll n);
	void bfs(ll v, bool visited[]);
	ll recurse(ll temp, vl &vect);
};
const int d4i[4] = { -1, 0, 1, 0}, d4j[4] = {0, 1, 0, -1};
const int d8i[8] = { -1, -1, 0, 1, 1, 1, 0, -1}, d8j[8] = {0, 1, 1, 1, 0, -1, -1, -1};
ll Graph::recurse(ll i, vl &dp) {
	if (dp[i] != -1) {
		return dp[i];
	}
	ll ans = 0;
	bool leaf = 1;
	for (auto it = adj_list[i].begin(); it != adj_list[i].end(); it++) {
		leaf = 0;
		ans = max(ans, recurse(*it, dp));
	}
	return dp[i] = leaf ? 0 : 1 + ans;
}
void solve() {
	ll vert, edge;
	read(vert, edge);
	Graph mygraph(vert);
	vl dp(vert, -1);
	ll st, ed;
	// cout << vert << " " << edge;
	fo(i, edge) {
		read(st, ed);
		mygraph.add_edge(--st, --ed, false);
	}
	// fo(i, vert) {
	// 	cout << i << "--->";
	// 	for (auto it = mygraph.adj_list[i].begin(); it != mygraph.adj_list[i].end(); it++) {
	// 		cout << *it << ",";
	// 	}
	// 	cout << "\n";
	// }
	for (ll i = vert - 1; i >= 0; i--) {
		dp[i] = mygraph.recurse(i, dp);
	}
	ll ans = INT_MIN;
	fo(i, vert) {
		ans = max(ans, dp[i]);
		// cout << dp[i] << " ";
	}
	cout << ans << endl;
	return ;
}
int main() {
	CP();
	// w(t) {
	solve();
	// }
	return 0;
}

Measured memory_bytes: 11248